﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;
using YJKArchUtils.Common;
using YJKRevitBase.WinForm;
using YRevitJig;
using YJKGeometryFuncs;
using YJKRevitView;
using YJKLoopSearch;

namespace YJKRevitBeam
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class CmdBeamsCreate : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			CmdViewType types = (CmdViewType)11;
			if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			Autodesk.Revit.DB.View activeView = cmdData.Application.ActiveUIDocument.ActiveView;
			if (!ViewHandle.ViewValidating(cmdData.Application.ActiveUIDocument.Document, activeView, ref message))
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			this.m_cmdData = cmdData;
			this.m_uiDoc = cmdData.Application.ActiveUIDocument;
			this.m_doc = cmdData.Application.ActiveUIDocument.Document;
			this.m_selection = cmdData.Application.ActiveUIDocument.Selection;
			RevitVersionFuncs.ClearSelection(this.m_selection);
			if (CmdBeamsCreate._hWndRevit == null)
			{
                CmdBeamsCreate._hWndRevit = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
			}
			BeamFormData beamFormData = new BeamFormData(cmdData);
			if (beamFormData.BeamSymbols.Count == 0)
			{
				YJKMessageBox.Show("当前样板下梁类型为空");
				return Autodesk.Revit.UI.Result.Failed;
			}
			BeamsCreateForm beamsCreateForm = new BeamsCreateForm(cmdData, beamFormData);
			beamsCreateForm.Show(CmdBeamsCreate._hWndRevit);
			int wMsg = 7;
			CmdBeamsCreate.SendMessage(CmdBeamsCreate._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Transaction transaction = new Transaction(cmdData.Application.ActiveUIDocument.Document, "批量生梁");
			XLineJig xlineJig = new XLineJig(this.m_uiDoc);
			try
			{
				for (;;)
				{
					transaction.Start();
					bool flag;
					if (beamsCreateForm.mode == 0)
					{
						flag = this.SelectTwoPoint(beamsCreateForm, xlineJig);
					}
					else if (1 == beamsCreateForm.mode)
					{
						flag = this.SelectOneGrid(beamsCreateForm);
					}
					else
					{
						flag = this.SelectMultiGrid(beamsCreateForm);
					}
					transaction.Commit();
					if (!flag)
					{
						if (!beamsCreateForm.clickModeBtn)
						{
							break;
						}
						beamsCreateForm.clickModeBtn = false;
					}
				}
			}
			catch (Exception ex)
			{
                string sss = ex.Message;
				transaction.RollBack();
				beamsCreateForm.Close();
				xlineJig.Dispose();
				return Autodesk.Revit.UI.Result.Failed;
			}
			beamsCreateForm.Close();
			xlineJig.Dispose();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		public bool SelectTwoPoint(BeamsCreateForm dlg, XLineJig jig)
		{
			XYZ xyz;
			XYZ xyz2;
			try
			{
				for (;;)
				{
					xyz = this.m_selection.PickPoint("请输入梁起始点");
					if (dlg.GetDlgBeamData().levels.Count > 0)
					{
						break;
					}
					TaskDialog.Show("盈建科", "标高列表不能空选。");
				}
				xyz2 = jig.PickEndPoint(xyz, "请输入梁终点");
				if (xyz2 == null)
				{
					return false;
				}
			}
			catch (Exception ex)
			{
                string sss = ex.Message;
				return false;
			}
			Curve curve = Line.CreateBound(xyz, xyz2);
			BeamData dlgBeamData;
			try
			{
				dlgBeamData = dlg.GetDlgBeamData();
			}
			catch
			{
				return true;
			}
			foreach (Level level in dlgBeamData.levels)
			{
				Level level2 = level as Level;
				if (level2 != null)
				{
					FamilyInstance familyInstance = this.CreateSingleBeam(curve, level2, dlgBeamData.beamEdge, dlgBeamData, true);
					double num = AssistFunc.mmToFeet(dlgBeamData.offsetEdgeZ);
					familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(num);
					familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(num);
				}
			}
			return true;
		}

		public bool SelectOneGrid(BeamsCreateForm dlg)
		{
			try
			{
				AxisFilter axisFilter = new AxisFilter();
				Reference reference;
				for (;;)
				{
					reference = this.m_selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, axisFilter, "请选择轴线");
					if (dlg.GetDlgBeamData().levels.Count > 0)
					{
						break;
					}
					TaskDialog.Show("盈建科", "标高列表不能空选。");
				}
				Element element = this.m_doc.GetElement(reference);
				List<Curve> selCurves = this.TransformCurvesByGrid(element);
				List<Curve> list = new List<Curve>();
				foreach (Element ele in AxisAssistFunc.GetAllAxis(this.m_cmdData.Application))
				{
					foreach (Curve item in this.TransformCurvesByGrid(ele))
					{
						list.Add(item);
					}
				}
				BeamData dlgBeamData;
				try
				{
					dlgBeamData = dlg.GetDlgBeamData();
				}
				catch
				{
					return true;
				}
				List<Curve> list2 = new List<Curve>();
				if (dlgBeamData.isSegment)
				{
					list2 = this.GetCurvesByBreak(selCurves, list);
				}
				else
				{
					list2 = this.GetCurvesNoBreak(selCurves, list);
				}
				if (list2 == null)
				{
					return true;
				}
				foreach (Level level in dlgBeamData.levels)
				{
					Level level2 = level as Level;
					if (level2 != null)
					{
						this.CreateMultipleBeam(list2, level2, dlgBeamData);
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		public bool SelectMultiGrid(BeamsCreateForm dlg)
		{
			try
			{
				AxisFilter axisFilter = new AxisFilter();
				IList<Element> list;
				for (;;)
				{
					list = this.m_selection.PickElementsByRectangle(axisFilter, "请框选轴网");
					if (list.Count < 3)
					{
						break;
					}
					if (dlg.GetDlgBeamData().levels.Count > 0)
					{
						goto IL_54;
					}
					YJKMessageBox.Show("标高列表不能空选");
				}
				YJKMessageBox.Show("请选择至少三根轴网");
				return true;
				IL_54:
				List<Element> list2 = new List<Element>();
				foreach (Element element in list)
				{
					if (element.GetType() == typeof(Grid))
					{
						list2.Add(element);
					}
				}
				AssistFunc.CompressArray(list2);
				List<Curve> list3 = new List<Curve>();
				foreach (Element ele in list2)
				{
					list3.AddRange(this.TransformCurvesByGrid(ele));
				}
				this.RemoveRepeatCurves(list3);
				BeamData dlgBeamData;
				try
				{
					dlgBeamData = dlg.GetDlgBeamData();
				}
				catch
				{
					return true;
				}
				List<Curve> curvesByBreak = this.GetCurvesByBreak(list3, list3);
				if (curvesByBreak == null || curvesByBreak.Count == 0)
				{
					YJKMessageBox.Show("请选择相交的轴网");
					return true;
				}
				this.RemoveRepeatCurves(curvesByBreak);
				foreach (Level level in dlgBeamData.levels)
				{
					Level level2 = level as Level;
					if (level2 != null)
					{
						this.CreateAreaBeam(curvesByBreak, level2, dlgBeamData);
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		protected List<FamilyInstance> CreateAreaBeam(List<Curve> curves, Level level, BeamData beamData)
		{
			List<Pole2D> list = new List<Pole2D>();
			int num = 0;
			foreach (Curve curve in curves)
			{
				Pole2D item = Pole2D.TransformWallToStructure2DPole(curve, new ElementId(num++), 0.0, 0.0);
				list.Add(item);
			}
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_cmdData);
			List<Curve> list2 = new List<Curve>();
			List<List<Curve>> fullFloorEdgeLoops = structureLoopSearcher.GetFullFloorEdgeLoops(list, ref list2, false, true, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
			List<FamilyInstance> list3 = new List<FamilyInstance>();
			foreach (List<Curve> list4 in fullFloorEdgeLoops)
			{
				foreach (Curve curve2 in list4)
				{
					FamilyInstance familyInstance = this.CreateSingleBeam(curve2, level, beamData.beamEdge, beamData, true);
					double num2 = AssistFunc.mmToFeet(beamData.offsetEdgeZ);
					familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(num2);
					familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(num2);
					list3.Add(familyInstance);
				}
			}
			foreach (Curve curve3 in list2)
			{
				FamilyInstance familyInstance2 = this.CreateSingleBeam(curve3, level, beamData.beamInner, beamData, false);
				double num3 = AssistFunc.mmToFeet(beamData.offsetInnerZ);
				familyInstance2.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(num3);
				familyInstance2.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(num3);
				list3.Add(familyInstance2);
			}
			return list3;
		}

		protected List<FamilyInstance> CreateMultipleBeam(List<Curve> curves, Level level, BeamData beamData)
		{
			List<FamilyInstance> list = new List<FamilyInstance>();
			foreach (Curve curve in curves)
			{
				FamilyInstance familyInstance = this.CreateSingleBeam(curve, level, beamData.beamEdge, beamData, true);
				double num = AssistFunc.mmToFeet(beamData.offsetEdgeZ);
				familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(num);
				familyInstance.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(num);
				list.Add(familyInstance);
			}
			return list;
		}

		protected FamilyInstance CreateSingleBeam(Curve curve, Level level, FamilySymbol beamType, BeamData beamData, bool edgeBeam = true)
		{
			UIApplication application = this.m_cmdData.Application;
			Curve curve2 = null;
			Arc arc = curve as Arc;
			if (null != arc)
			{
				XYZ endPoint;
				XYZ endPoint2;
				if (arc.Normal.Z < 0.0)
				{
					endPoint = curve.GetEndPoint(1);
					endPoint2 = curve.GetEndPoint(0);
				}
				else
				{
					endPoint = curve.GetEndPoint(0);
					endPoint2 = curve.GetEndPoint(1);
				}
				XYZ center = arc.Center;
				XYZ xyz = new XYZ(center.X, center.Y, level.Elevation);
				double num = arc.Radius;
				if (edgeBeam)
				{
					num += AssistFunc.mmToFeet(beamData.offsetEdgeXY);
				}
				else
				{
					num += AssistFunc.mmToFeet(beamData.offsetInnerXY);
				}
				double num2 = XYZ.BasisX.AngleOnPlaneTo(endPoint - center, XYZ.BasisZ);
				double num3 = XYZ.BasisX.AngleOnPlaneTo(endPoint2 - center, XYZ.BasisZ);
				if (num3 < num2)
				{
					num2 -= Math.PI*2;
				}
				curve2 = Arc.Create(xyz, num, num2, num3, XYZ.BasisX, XYZ.BasisY);
			}
			Line line = curve as Line;
			if (null != line)
			{
				XYZ endPoint3 = curve.GetEndPoint(0);
				XYZ endPoint4 = curve.GetEndPoint(1);
				XYZ xyz2 = new XYZ(endPoint3.X, endPoint3.Y, level.Elevation);
				XYZ xyz3 = new XYZ(endPoint4.X, endPoint4.Y, level.Elevation);
				XYZ xyz4 = AxisAssistFunc.RotateTo(xyz3 - xyz2, -Math.PI*.5, XYZ.BasisZ).Normalize();
				if (edgeBeam)
				{
					xyz4 *= AssistFunc.mmToFeet(beamData.offsetEdgeXY);
				}
				else
				{
					xyz4 *= AssistFunc.mmToFeet(beamData.offsetInnerXY);
				}
				xyz2 += xyz4;
				xyz3 += xyz4;
				curve2 = Line.CreateBound(xyz2, xyz3);
			}
			if (null == curve2)
			{
				return null;
			}
            StructuralType structuralType = (StructuralType)1;
			UnifiedModified.ActivateFamilySymbol(beamType);
			return this.m_cmdData.Application.ActiveUIDocument.Document.Create.NewFamilyInstance(curve2, beamType, level, structuralType);
		}

		private List<Curve> TransformCurvesByGrid(Element ele)
		{
			List<Curve> list = new List<Curve>();
			if (ele.GetType() == typeof(MultiSegmentGrid))
			{
				MultiSegmentGrid grid = ele as MultiSegmentGrid;
				list = AxisAssistFunc.GetLocationCurves(this.m_cmdData.Application, this.m_cmdData.Application.ActiveUIDocument.Document, grid);
			}
			else if (ele.GetType() == typeof(Grid))
			{
				Grid grid2 = ele as Grid;
				list.Add(grid2.Curve);
			}
			return list;
		}

		private List<Curve> GetCurvesByBreak(List<Curve> selCurves, List<Curve> allCurves)
		{
			IntersectionResultArray intersectionResultArray = null;
			List<Curve> list = new List<Curve>();
			foreach (Curve curve in selCurves)
			{
				List<XYZ> list2 = new List<XYZ>();
				foreach (Curve curve2 in allCurves)
				{
					if (!curve.Equals(curve2))
					{
						SetComparisonResult setComparisonResult = curve.Intersect(curve2, out intersectionResultArray);
						if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
						{
							for (int i = 0; i < intersectionResultArray.Size; i++)
							{
								list2.Add(intersectionResultArray.get_Item(i).XYZPoint);
							}
						}
					}
				}
				AssistFunc.CompressArray(list2);
				this.SortPoint(curve, ref list2);
				Line line = curve as Line;
				if (null != line)
				{
					for (int j = 0; j < list2.Count - 1; j++)
					{
						if (!list2[j].IsAlmostEqualTo(list2[j + 1]))
						{
							Curve item = Line.CreateBound(list2[j], list2[j + 1]);
							if (!list.Contains(item))
							{
								list.Add(item);
							}
						}
					}
				}
				Arc arc = curve as Arc;
				if (null != arc)
				{
					for (int k = 0; k < list2.Count - 1; k++)
					{
						if (!list2[k].IsAlmostEqualTo(list2[k + 1]))
						{
							XYZ xyz = AxisAssistFunc.CalculatMidPoint(list2[k], list2[k + 1], arc.Center, XYZ.BasisZ);
							Curve item2 = Arc.Create(list2[k], list2[k + 1], xyz);
							if (!list.Contains(item2))
							{
								list.Add(item2);
							}
						}
					}
				}
			}
			return list;
		}

		private List<Curve> GetCurvesNoBreak(List<Curve> selCurves, List<Curve> allCurves)
		{
			IntersectionResultArray intersectionResultArray = null;
			List<Curve> list = new List<Curve>();
			Stack<Curve> stack = new Stack<Curve>();
			int num = 0;
			foreach (Curve curve in selCurves)
			{
				if (num == 0)
				{
					List<XYZ> list2 = new List<XYZ>();
					foreach (Curve curve2 in allCurves)
					{
						if (!curve.Equals(curve2))
						{
							SetComparisonResult setComparisonResult = curve.Intersect(curve2, out intersectionResultArray);
							if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
							{
								for (int i = 0; i < intersectionResultArray.Size; i++)
								{
									list2.Add(intersectionResultArray.get_Item(i).XYZPoint);
								}
							}
						}
					}
					if (list2.Count > 0)
					{
						this.SortPoint(curve, ref list2);
						Curve subCurve = this.GetSubCurve(curve, list2[0], curve.GetEndPoint(1));
						if (null != subCurve)
						{
							stack.Push(subCurve);
						}
						num++;
					}
				}
				else
				{
					stack.Push(curve);
				}
			}
			num = 0;
			while (stack.Count > 0)
			{
				if (num == 0)
				{
					Curve curve3 = stack.Pop();
					List<XYZ> list3 = new List<XYZ>();
					foreach (Curve curve4 in allCurves)
					{
						SetComparisonResult setComparisonResult = curve3.Intersect(curve4, out intersectionResultArray);
						if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
						{
							for (int j = 0; j < intersectionResultArray.Size; j++)
							{
                                list3.Add(intersectionResultArray.get_Item(j).XYZPoint);
							}
						}
					}
					if (list3.Count > 0)
					{
						this.SortPoint(curve3, ref list3);
						Curve subCurve2 = this.GetSubCurve(curve3, curve3.GetEndPoint(0), list3[list3.Count - 1]);
						if (null != subCurve2)
						{
							list.Add(subCurve2);
						}
						num++;
					}
				}
				else
				{
					list.Add(stack.Pop());
				}
			}
			list.Reverse();
			return list;
		}

		private Curve GetSubCurve(Curve oriCurves, XYZ pt1, XYZ pt2)
		{
			if (pt1.IsAlmostEqualTo(pt2))
			{
				return null;
			}
			Line line = oriCurves as Line;
			if (null != line)
			{
				return Line.CreateBound(pt1, pt2);
			}
			Arc arc = oriCurves as Arc;
			if (null != arc)
			{
				XYZ xyz = AxisAssistFunc.CalculatMidPoint(pt1, pt2, arc.Center, arc.Normal);
				return Arc.Create(pt1, pt2, xyz);
			}
			return null;
		}

		private void RemoveRepeatCurves(List<Curve> oriCurves)
		{
			List<Curve> list = new List<Curve>();
			foreach (Curve curve in oriCurves)
			{
				bool flag = false;
				foreach (Curve c in list)
				{
					if (OverlapType.eOverlap == CurveAssistFunc.GetOverlapType(this.m_cmdData.Application, curve, c))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list.Add(curve);
				}
			}
			oriCurves.Clear();
			oriCurves.AddRange(list);
		}

		private void SortPoint(Curve curve, ref List<XYZ> points)
		{
			Line line = curve as Line;
			if (null != line)
			{
                points.Sort(new YJKArchUtils.Utils.Generics.DistanceComparer(line.GetEndPoint(0)));
			}
			Arc arc = curve as Arc;
			if (null != arc)
			{
				XYZ center = arc.Center;
				XYZ endPoint = arc.GetEndPoint(1);
				if (arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
				{
					endPoint = arc.GetEndPoint(0);
				}
                points.Sort(new YJKGeometryFuncs.RotationComparer(endPoint, center));
			}
		}

		private ExternalCommandData m_cmdData;

		private UIDocument m_uiDoc;

		private Document m_doc;

		private Selection m_selection;

        public static WindowHandle _hWndRevit;
	}
}
